package com.snail.manager;

import com.snail.config.MinioConfig;
import com.snail.model.entity.MarkdownSaveRequest;
import com.zhipu.oapi.ClientV4;
import com.zhipu.oapi.Constants;
import com.zhipu.oapi.service.v4.model.*;

import io.minio.*;
import io.minio.errors.ErrorResponseException;
import io.reactivex.Flowable;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.io.ByteArrayInputStream;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;


@Component
@Slf4j
public class AiManager {
    @Resource
    private ClientV4 client;
    @Resource
    private MinioClient minioClient;

    @Value("${minio.bucket.doc}")
    private String docBucket;

    // 默认的是0.95，认为此时是稳定的
    // 较稳定的随机数
    public static final float STABLE_TEMPERATURE = 0.05f;
    // 不稳定的随机数
    public static final float UNSTABLE_TEMPERATURE = 0.99f;

    /**
     * 通用请求方法
     *
     * @param aiChatMessages AI聊天消息
     * @param stream 是否开启流式
     * @param temperature 随机性
     * @return AI响应信息
     */
    public String doRequest(List<ChatMessage> aiChatMessages, Boolean stream, Float temperature) {
        ChatCompletionRequest chatCompletionRequest = ChatCompletionRequest.builder()
                .model(Constants.ModelChatGLM4)
                .stream(stream)
                .invokeMethod(Constants.invokeMethod)
                .temperature(temperature)
                .messages(aiChatMessages)
                .build();
        try {
            ModelApiResponse invokeModelApiResp = client.invokeModelApi(chatCompletionRequest);
            return invokeModelApiResp.getData().getChoices().get(0).getMessage().getContent().toString();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return "";
    }

    /**
     * 简化消息传递
     *
     * @param systemMessage 系统信息
     * @param userMessage 用户信息
     * @param stream 是否开启流式
     * @param temperature 随机性
     * @return AI响应信息
     */
    public String doRequest(String systemMessage, String userMessage, Boolean stream, Float temperature) {
        // 构造请求
        List<ChatMessage> aiChatMessages = new ArrayList<>();
        ChatMessage systemChatMessage = new ChatMessage(ChatMessageRole.SYSTEM.value(), systemMessage);
        ChatMessage userChatMessage = new ChatMessage(ChatMessageRole.USER.value(), userMessage);
        aiChatMessages.add(systemChatMessage);
        aiChatMessages.add(userChatMessage);
        return doRequest(aiChatMessages, stream, temperature);
    }

    /**
     * 同步请求
     *
     * @param systemMessage 系统信息
     * @param userMessage 用户信息
     * @param temperature 随机性
     * @return AI响应信息
     */
    public String doSyncRequest(String systemMessage, String userMessage, Float temperature) {
        return doRequest(systemMessage, userMessage, Boolean.FALSE, temperature);
    }

    /**
     * 同步请求（答案较稳定）
     *
     * @param systemMessage 系统信息
     * @param userMessage 用户信息
     * @return AI响应信息
     */
    public String doSyncStableRequest(String systemMessage, String userMessage) {
        return doRequest(systemMessage, userMessage, Boolean.FALSE, STABLE_TEMPERATURE);
    }

    /**
     * 同步请求（答案较随机）
     *
     * @param systemMessage 系统提示，指导AI如何响应
     * @param userMessage 用户输入的问题或请求
     *@param saveRequest 保存配置对象，控制是否及如何保存结果
     * @return AI响应信息
     * 目前使用此方法**********************************************
     */
    /**
     * 同步请求（支持Function Calling控制存储）
     */
    public String doSyncUnStableRequest(String systemMessage, String userMessage) {
        String rawResponse = doRequest(systemMessage, userMessage, Boolean.FALSE, UNSTABLE_TEMPERATURE);

        // 提取纯文本内容
//        String pureContent = extractPureContent(rawResponse);

        // 通过Function Calling控制是否存储
//        if (saveRequest != null && Boolean.TRUE.equals(saveRequest.getEnable())) {
//            savePureContentToMinio(rawResponse, saveRequest);
//        }
        //
        return rawResponse;
    }

    /**
     * 从原始响应中提取纯文本内容
     */
//    private String extractPureContent(String rawResponse) {
//        int contentStart = rawResponse.indexOf("content=") + 8;//找到content=的位置，跳过前面的字符
//        int contentEnd = rawResponse.indexOf(", name="); //找到content=和name=之间的位置
//        // 确保跳过了content=       确保结束位置在name=之前
//        if (contentStart > 7 && contentEnd > contentStart) {
//            //提取"content="和"name="之间的纯文本内容                           移除首尾空白符
//            String content = rawResponse.substring(contentStart, contentEnd).trim();
//            // 移除可能的多余引号
//            if (content.startsWith("\"") && content.endsWith("\"")) {
//                content = content.substring(1, content.length() - 1);
//            }
//            return content;
//        }
//        return rawResponse; // 如果解析失败返回原始内容
//    }

    /**
     * 将纯文本内容保存到MinIO  方法二：支持Function Calling参数控制（只保存纯文本内容）
     */
    private void savePureContentToMinio(String content, MarkdownSaveRequest saveRequest) {
        try {
            // 1. 确定存储参数
            String bucketName = Optional.ofNullable(saveRequest.getBucketName())
                    .orElse(docBucket);
            String fileName = buildFileName(saveRequest.getFileNamePrefix());

            // 2. 确保minio存储桶存在
            ensureBucketExists(bucketName);

            // 3. 构建纯文本内容(简化格式)
            String pureContent = "# AI生成内容\n\n" + content;

            // 4. 检查文件是否已存在(如果配置不允许覆盖)
            if (Boolean.FALSE.equals(saveRequest.getOverwrite())) {
                checkFileNotExists(bucketName, fileName);
            }

            // 5. 上传到MinIO
            uploadToMinio(bucketName, fileName, pureContent);

            log.info("纯文本内容已存储到MinIO: {}/{}", bucketName, fileName);
        } catch (Exception e) {
            log.error("MinIO存储失败: {}", e.getMessage());
            throw new RuntimeException("文件存储失败: " + e.getMessage(), e);
        }
    }

    /**
     * 增强版Markdown保存（支持Function Calling参数控制） 方法一：直接保存
     */
    private void saveToMinioWithFunctionCall(String systemPrompt, String userPrompt,
                                             String response, MarkdownSaveRequest saveRequest) {
        try {
            // 1. 确定存储参数(桶名称、文件名)
            String bucketName = Optional.ofNullable(saveRequest.getBucketName())
                    .orElse(docBucket);

            String fileName = buildFileName(saveRequest.getFileNamePrefix());

            // 2. 检查存储桶是否存在，不存在则创建
            ensureBucketExists(bucketName);

            // 3. 构建Markdown格式的内容(包含系统提示、用户提示和AI响应)
            String markdownContent = buildMarkdownContent(systemPrompt, userPrompt, response);

            // 4. 检查文件是否已存在(如果配置不允许覆盖)
            if (Boolean.FALSE.equals(saveRequest.getOverwrite())) {
                checkFileNotExists(bucketName, fileName);
            }

            // 5. 上传到MinIO对象存储
            uploadToMinio(bucketName, fileName, markdownContent);

            log.info("Markdown文件已存储到MinIO: {}/{}", bucketName, fileName);
        } catch (Exception e) {
            log.error("MinIO存储失败: {}", e.getMessage());
            throw new RuntimeException("文件存储失败: " + e.getMessage(), e);
        }
    }

    // --- 辅助方法 ---

    /**
     * 生成带时间戳的文件名，格式如："ai_response_20230716_143022.md"
     * @return
     */
    private String buildFileName(String prefix) {
        String filePrefix = Optional.ofNullable(prefix).orElse("user_note_");
        return filePrefix + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMdd_HHmmss")) + ".md";
    }

    /**
     * 将系统提示、用户提示和AI响应组合成Markdown格式的字符串
     * @return
     */
    private String buildMarkdownContent(String systemPrompt, String userPrompt, String response) {
        return String.format("# AI Response\n\n## System Prompt\n```\n%s\n```\n\n" +
                        "## User Prompt\n```\n%s\n```\n\n## AI Response\n```\n%s\n```\n",
                systemPrompt, userPrompt, response);
    }

    /**
     * 确保指定的MinIO存储桶存在，不存在则创建
     */
    private void ensureBucketExists(String bucketName) throws Exception {
        if (!minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build())) {
            minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
        }
    }

    /**
     * 检查文件是否已存在(当配置不允许覆盖时使用)
     */
    private void checkFileNotExists(String bucketName, String fileName) throws Exception {
        try {
            minioClient.statObject(StatObjectArgs.builder()
                    .bucket(bucketName)
                    .object(fileName)
                    .build());
            throw new RuntimeException("文件已存在且不允许覆盖: " + fileName);
        } catch (ErrorResponseException e) {
            if (!e.getMessage().contains("Not Found")) {
                throw e;
            }
        }
    }

    /**
     * 实际执行文件上传到MinIO的操作
     */
    private void uploadToMinio(String bucketName, String fileName, String content) throws Exception {
        minioClient.putObject(
                PutObjectArgs.builder()
                        .bucket(bucketName)
                        .object(fileName)
                        .contentType("text/markdown")
                        .stream(
                                new ByteArrayInputStream(content.getBytes(StandardCharsets.UTF_8)),
                                content.getBytes(StandardCharsets.UTF_8).length,
                                -1
                        )
                        .build());
    }

    /**
     * 通用流式请求
     *
     * @param aiChatMessages AI聊天消息
     * @param temperature    随机性
     * @return AI响应信息(流式)
     */
    public Flowable<ModelData> doStreamRequest(List<ChatMessage> aiChatMessages, Float temperature) {
        ChatCompletionRequest chatCompletionRequest = ChatCompletionRequest.builder()
                .model(Constants.ModelChatGLM4)
                .stream(Boolean.TRUE)
                .invokeMethod(Constants.invokeMethod)
                .temperature(temperature)
                .messages(aiChatMessages)
                .build();
        ModelApiResponse modelApiResponse = client.invokeModelApi(chatCompletionRequest);
        return modelApiResponse.getFlowable();
    }



    /**
     * 通用流式请求(简化消息传递)
     *
     * @param systemMessage 系统信息
     * @param userMessage 用户信息
     * @param temperature 随机性
     * @return AI响应信息(流式)
     */
    public Flowable<ModelData> doStreamRequest(String systemMessage, String userMessage, Float temperature) {
        List<ChatMessage> aiChatMessages = new ArrayList<>();
        ChatMessage systemChatMessage = new ChatMessage(ChatMessageRole.SYSTEM.value(), systemMessage);
        ChatMessage userChatMessage = new ChatMessage(ChatMessageRole.USER.value(), userMessage);
        aiChatMessages.add(systemChatMessage);
        aiChatMessages.add(userChatMessage);
        System.out.println("aiChatMessages: " + aiChatMessages);
        return doStreamRequest(aiChatMessages, temperature);
    }
}
